#ifndef _DIRECTORY_H
#define	_DIRECTORY_H

#include <vector>
#include "FreeList.h"
#include "FSBlock.h"
#include "DirectoryEntry.h"


using namespace std;

/*
 * Directory.h
 *
 * Created on March 8, 2005, 8:29 PM
 * Modified: CGP; 2/5/09
 *      Converted to C++ from Java.
 */


/** This class provides basic directory support, on top of the BlockGroup class.
 * Only a single directory is provided, and this is represented as a single
 * BlockGroup. The start and end block numbers for the Directory are contained in the
 * master block, after the start and end block numbers for the free list.
 *
 * @author chris
 */
class Directory
{
private:
    /** The number of directory entries per block in a BlockGroup.
     */
    int ENTRIES_PER_BLOCK; // see constructor

    // The FreeList to use to allocate blocks for the directory.
    FreeList *m_freeList;

    // The block group for the directory.
    BlockGroup *m_directory;

    // The number of files represented in the directory.
    // get this from m_entries.size()
    // private int m_numberOfFiles = 0;

    // Maintain the Directory in RAM as a Vector of DirectoryEntry's
    vector<DirectoryEntry *> m_entries;

    // Master block
    FSBlock *m_dmBlock;
    
    /** Opens an existing directory. It must have been created before using the
     * Directory constructor with the create=true setting. Reads the start & end block
     * numbers from the master block, and reads the number of files currently represented
     * by the directory.
     */
    void OpenDirectory();
    
    /** Creates a new BlockGroup for the directory, and writes:
     *      the start and end block;
     *      the number of blocks in the directory;
     *      and the number of files
     * for that block group to the master block.
     */
    void CreateDirectory();
    
    /** Update master block with the current information about the m_directory BlockGroup.
     */
    void UpdateMasterBlock();

    /** Lookup a directory entry. If the entry is not found, -1 is returned.
     *
     * @return the m_entries index for the directory entry, if found.
     */
    int LookUpByPosition(const char *name);
    
    /** Deletes all DirectoryEntry's in the m_entries cache.
     */
    void DeleteCache();
    
public:
    /** If create=true, this creates a new, empty directory.
     * The start and end block numbers are written to the master block.
     * If create=false, this reads the start and end block numbers from the
     * master block.
     *
     * @param freeList must be the free list for a Disk.
     */
    Directory(FreeList *freeList, bool create);

    /** This deletes the directory for a disk. After this call, no Disk blocks are allocated
     * for the directory. It is your responsiblity to delete any BlockGroups associated with
     * files stored as entries in the Directory.
     */
    void Delete();

    /** Flushes the Directory to the Disk. This must be called to maintain integrity of
     * the Directory structure. In addition to writing out the directory entries to the
     * blocks of the directory BlockGroup, this updates the master block with the
     * information for the m_directory.
     */
    void Flush();

    /** Close the directory. Similar to Flush(), except that you cannot use the
     * Directory after this call.
     */
    void Close();

    /** Returns the vector of directory entries currently contained in the directory.
     * The vector will have size() 0 if there are no entries.
     * A reference to the data structure
     * contained internally is returned. The caller should not modify this data structure.
     *
     * @returns a pointer to an STL vector of DirectoryEntry objects.
     */
    vector<DirectoryEntry *> *GetEntries();

    /** Lookup a directory entry. If the entry is not found, null is returned.
     */
    DirectoryEntry *LookUp(const char *name);

    /** Returns true iff a directory entry could be found.
     */
    bool FindEntry(const char *name);

    /** Creates a new entry in the Directory, for a file. The caller is responsible
     * for creating a BlockGroup for the file, and keeping the info in the Directory
     * synchronized with the info in the file's BlockGroup.
     *
     * The name given must be unique
     * across all of the other file names that are presently in the directory.
     * The caller is responsible for allocating the FCB for the file (i.e., for changing
     * the FCB part of the DirectoryEntry to initial 0/NULL values.
     *
     * @return new DirectoryEntry iff entry could be added. If it could not be added
     *      returns NULL (e.g., if the name was already in the Directory). The Directory
     *      class retains ownership of the DirectoryEntry object that is returned. That is,
     *      the caller should not delete this object.
     */
    DirectoryEntry *CreateNewEntry(const char *name);
    
    /** Deletes a file entry in the directory. Does not update the directory on Disk;
     * you must call Flush or Close to do that.
     *
     * @return true iff entry could be deleted.
     */
    bool DeleteEntry(const char *name);

    /** Rename a file. Doesn't write the modified directory to the Disk. Call Flush
     * or Close to do that.
     *
     * @return true iff entry could be renamed.
     */
    bool RenameEntry(char *oldName, char *newName);

    /** To be used from a web page to test the binary format of file system.
     * This was not needed in student's assignments. I used it for the web-based
     * testing I provided.
     */
    static void WebTest(const char *filename);

    /** Carry out menu-based testing.
     */
    static void Test();
};



#endif	/* _DIRECTORY_H */

